package com.maodou.core.network

/**
 * Extension utilities for NetworkResult/NetworkError to make error handling and
 * success chaining more convenient.
 */

// ----- NetworkResult operators (non-Flow) -----
inline fun <T, R> NetworkResult<T>.mapSuccess(transform: (T) -> R): NetworkResult<R> =
    when (this) {
        is NetworkResult.Success -> NetworkResult.Success(transform(this.data))
        is NetworkResult.Failure -> NetworkResult.Failure(this.error)
    }

inline fun <T, R> NetworkResult<T>.flatMapSuccess(transform: (T) -> NetworkResult<R>): NetworkResult<R> =
    when (this) {
        is NetworkResult.Success -> transform(this.data)
        is NetworkResult.Failure -> NetworkResult.Failure(this.error)
    }

inline fun <T> NetworkResult<T>.onSuccess(action: (T) -> Unit): NetworkResult<T> =
    also { if (it is NetworkResult.Success) action(it.data) }

inline fun <T> NetworkResult<T>.onFailure(action: (NetworkError) -> Unit): NetworkResult<T> =
    also { if (it is NetworkResult.Failure) action(it.error) }

fun <T> NetworkResult<T>.getOrNull(): T? = (this as? NetworkResult.Success<T>)?.data
fun <T> NetworkResult<T>.errorOrNull(): NetworkError? = (this as? NetworkResult.Failure)?.error

inline fun <T> NetworkResult<T>.recover(transform: (NetworkError) -> T): NetworkResult<T> =
    when (this) {
        is NetworkResult.Success -> this
        is NetworkResult.Failure -> NetworkResult.Success(transform(this.error))
    }

// ----- Error helpers -----
fun NetworkError.isUnauthorized(): Boolean =
    this is NetworkError.Http && (this.code == 401 || this.code == 403)

fun NetworkError.isServerError(): Boolean =
    this is NetworkError.Http && this.code >= 500

fun <T> NetworkResult<T>.isUnauthorized(): Boolean =
    (this as? NetworkResult.Failure)?.error?.isUnauthorized() == true

fun <T> NetworkResult<T>.isServerError(): Boolean =
    (this as? NetworkResult.Failure)?.error?.isServerError() == true

fun NetworkError.httpCodeOrNull(): Int? = (this as? NetworkError.Http)?.code
fun <T> NetworkResult<T>.httpCodeOrNull(): Int? = (this as? NetworkResult.Failure)?.error?.httpCodeOrNull()

// ----- Error info extraction helpers -----
fun NetworkError.messageOrNull(): String? = when (this) {
    is NetworkError.Http -> this.message
    is NetworkError.Business -> this.message
    is NetworkError.Network -> this.cause.localizedMessage
    is NetworkError.Serialization -> this.cause.localizedMessage ?: "数据解析失败"
    is NetworkError.Unknown -> this.cause?.localizedMessage
}

fun <T> NetworkResult<T>.messageOrNull(): String? =
    (this as? NetworkResult.Failure)?.error?.messageOrNull()

fun NetworkError.isBusinessError(): Boolean = this is NetworkError.Business

fun NetworkError.businessCodeOrNull(): String? = (this as? NetworkError.Business)?.code

fun NetworkError.codeTextOrNull(): String? = when (this) {
    is NetworkError.Http -> this.code.toString()
    is NetworkError.Business -> this.code
    else -> null
}

fun <T> NetworkResult<T>.codeTextOrNull(): String? =
    (this as? NetworkResult.Failure)?.error?.codeTextOrNull()

fun NetworkError.toUserMessage(fallback: String = "请求失败，请稍后重试"): String =
    messageOrNull() ?: fallback

fun <T> NetworkResult<T>.toUserMessage(fallback: String = "请求失败，请稍后重试"): String =
    (this as? NetworkResult.Failure)?.error?.toUserMessage(fallback) ?: fallback